/* Copyright (c) 2002  Michael Stumpf  <mistumpf@de.pepperl-fuchs.com>
   Copyright (c) 2006  Dmitry Xmelkov
   Copyright (c) 2008  Ruud v Gessel
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.
   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. */

/* $Id: fp_rempio2.S 1810 2008-12-02 13:34:42Z dmix $ */

#include "fp32def.h"
#include "asmdef.h"

/* <non_standart> __fp_rempio2 (float x);
     The __fp_rempio2() function computes the remainder of dividing
     absolute value of x by Pi/2. The return value is x - n*Pi/2, where
     n is the quotient of abs(x)/(Pi/2), rounded towards zero to an integer.
   Output:
	rA3.rA2.rA1.rA0.rAE	- flt40_t remainder
	ZL			- low byte of n
 */

#define	HI40_PIO2	0x3FC90FDA	/* (flt40_t) Pi/2	*/
#define	LO40_PIO2	0xA2

FUNCTION __fp_rempio2

0:	rjmp	_U(__fp_nan)

ENTRY __fp_rempio2
  ; split and check finite
	rcall	_U(__fp_splitA)
	brcs	0b		; only finite numbers are valid
	clt			; ignore a sign
  ; init division result
	ldi	ZL, 0
  ; extend A
	clr	rAE
  ; check (and modify) exponent
	subi	rA3, hhi8(HI40_PIO2 << 1)
	brlo	5f		; fabs(A) < 1.0 radian, C is set
  ; prepare loop
	ldi	rB0,  lo8(HI40_PIO2)
	ldi	rB1,  hi8(HI40_PIO2)
	ldi	rB2, hlo8(HI40_PIO2 | 0x800000)		; + hidden bit
	rjmp	1f

.Loop:	lsl	ZL
	lsl	rAE
	rol	rA0
	rol	rA1
	rol	rA2
	brcs	2f
1:	cpi	rAE, lo8(LO40_PIO2)
	cpc	rA0, rB0
	cpc	rA1, rB1
	cpc	rA2, rB2
	brlo	3f
2:	subi	rAE, lo8(LO40_PIO2)
	sbc	rA0, rB0
	sbc	rA1, rB1
	sbc	rA2, rB2
	inc	ZL
3:	dec	rA3
	brpl	.Loop

  ; Normalize, we know that rA2.1.0.E >= 0x0E. You can check this with
  ; a test program below.
	cpi	rA2,0x80
	brcc	5f
4:	dec	rA3
	lsl	rAE
	rol	rA0
	rol	rA1
	rol	rA2			; C := 0
	brpl	4b

5:	sbci	rA3, hhi8((HI40_PIO2<<1) + 0x01000000)	; undo the subi 0x7f
	rjmp	_U(__fp_mpack_finite)
ENDFUNC

#if 0
/* This is a test program to find the smallest value of rA2.1.0.E after
   division. The nonzero value gives a garanty that normalization loop
   is finite.	*/

#include <stdio.h>
#define	MNT32_PIO2	0xC90FDAA2

int main ()
{
    unsigned long rA210;
    unsigned long rA210E;
    int rA3;
    unsigned long c;
    unsigned long amin = 0xffffffff;

    for (rA210 = 0x800000; rA210 <= 0xffffff; rA210 += 1) {
	rA210E = rA210 << 8;
	c = 0;
	rA3 = 127;	/* this is max for finite number	*/
	goto m;
	do {
	    c = rA210E & 0x80000000;
	    rA210E <<= 1;
	  m:
	    if (c || (rA210E >= MNT32_PIO2))
		rA210E -= MNT32_PIO2;
	    if (rA210E < amin) {
		amin = rA210E;
	        printf ("min of rA210E: 0x%08lx\r", amin);
		fflush (stdout);
	    }
	} while (--rA3 >= 0);
    }
    putchar ('\n');
    return 0;
}
#endif
